#include "Robot.h"
#include <stdio.h>
#include <math.h>

#define PI 3.14
//#define PI 3.14159265
const int VECTOR_LENGHT = 5;
const int SPEED_RANDOM_ROBOT = 15;
static const int LIFE = 20;

//modify the for loop (use iterators instead)
Robot::Robot(Map *m)
{
	map = m;
	numberElements = 0;
	x = 0;
	y = 0;
	z = 0;
	height = 0;
	angle = angleCam = angleCamTilt = 0;
	sizeX = 0;
	sizeZ = 0;
	life = maxLife = LIFE;
	destroyed = false;
	deleteO = false;
	randomFlag = false;
	currentTexture = 0;

	// init the parts
	antigravUnit = 0;
	bipod = 0;
	cannon = 0;
	missiles = 0;
	nuclear = 0;
	eBrain = 0;
	phaser = 0;
	tracks = 0;
	missilesMunition = 0;
	cannonMunition = 0;
	phaserMunition = 0;
	pc = 0;
	for(int i = 0; i!=6; ++i)
	{
		vect[i] = 0;
	}
	addCamera();
	light_direction[0] = 0;
	light_direction[1] = 0;
	light_direction[2] = 0;

	robotLight = new spotLight();
	robotLight->setDirection(light_direction[0], light_direction[1], light_direction[2]);
	robotLight->setPosition(x,y,z);

	setBoundaries();
	loadImageLife();
}

void Robot::loadImageLife()
{
	Image* image = loadBMP("textures\\life.bmp");
	textureLife = loadTexture(image);
	delete image;
}

void Robot::random()
{
	randomFlag = true;
	timerRandom = 0;
}

bool Robot::isRandom()
{
	return randomFlag;
}

void Robot::setBoundaries()
{
	sizeX = map->getWidth();
	sizeZ = map->getLength();
}

void Robot::addBipod()
{
	bipod = new Bipod;
	vect[0] = bipod;
	height+=bipod->getHeight();
	refreshPositionCamera();
	++numberElements;
}

void Robot::addAntiGrav()
{
	antigravUnit = new AntiGrav;
	vect[0] = antigravUnit;
	height+=antigravUnit->getHeight();
	refreshPositionCamera();
	++numberElements;
}

void Robot::addTracks()
{
	tracks = new Tracks;
	vect[0] = tracks;
	height+=tracks->getHeight();
	refreshPositionCamera();
	++numberElements;
}

void Robot::addCannon(int pos)
{
	cannon = new Cannon;
	cannonMunition = new CannonMunition(map);
	cannon->setAngle(angle);
	vect[pos] = cannon;
	height+=cannon->getHeight();
	refreshPositionCamera();
	++numberElements;
}

void Robot::addMissile(int pos)
{
	missiles = new Missiles;
	missilesMunition = new MissileMunition(map);
	missiles->setAngle(angle);
	vect[pos] = missiles;
	height+=missiles->getHeight();
	refreshPositionCamera();
	++numberElements;
}

void Robot::addNuclear(int pos)
{
	nuclear = new Nuclear;
	vect[pos] = nuclear;
	height+=nuclear->getHeight();
	refreshPositionCamera();
	++numberElements;

	// upgrades for munitions
	if (missilesMunition)
		missilesMunition->setDamage(nuclear->getUpgradePower());
	if(cannonMunition)
		cannonMunition->setDamage(nuclear->getUpgradePower());
	if(phaserMunition)
		phaserMunition->setDamage(nuclear->getUpgradePower());

	// upgrades for life
	life += nuclear->getUpgradeLife();
	maxLife = life;
}

void Robot::addEBrain(int pos)
{
	eBrain = new Electric_Brain;
	vect[pos] = eBrain;
	height+=eBrain->getHeight();
	refreshPositionCamera();
	++numberElements;
	
	// upgrades for munitions
	if (missilesMunition)
		missilesMunition->setDamage(eBrain->getUpgradePower());
	if(cannonMunition)
		cannonMunition->setDamage(eBrain->getUpgradePower());
	if(phaserMunition)
		phaserMunition->setDamage(eBrain->getUpgradePower());

	// upgrades for life
	life += eBrain->getUpgradeLife();
	maxLife = life;
}

void Robot::addPhaser(int pos)
{
	phaser = new Phaser;
	phaserMunition = new PhaserMunition(map);
	vect[pos] = phaser;
	height+=phaser->getHeight();
	refreshPositionCamera();
	++numberElements;
}

void Robot::finished()
{
	for (int i =0; i!=6; ++i){
		if (vect[i] != 0){
			for (int j = 0; j!=i; ++j)
				vect[i]->setElevation(vect[j]->getHeight());
		}
	}

	if(missilesMunition)
		missilesMunition->setElevation(missiles->getElevation() + missiles->getHeight()/2);
	if(cannonMunition)
		cannonMunition->setElevation(cannon->getElevation() + cannon->getHeight()/2);
	if(phaserMunition)
		phaserMunition->setElevation(phaser->getElevation() + phaser->getHeight()/2);

	// current texture
	if(bipod)
		currentTexture = bipod->getTexture();
	else if(antigravUnit)
		currentTexture = antigravUnit->getTexture();
	else if(tracks)
		currentTexture = tracks->getTexture();
}

GLfloat Robot::getX()
{
	return x;
}

GLfloat Robot::getY()
{
	return y;
}

GLfloat Robot::getZ()
{
	return z;
}

GLfloat Robot::getHeight()
{
	return height;
}

GLfloat Robot::getAngle()
{
	return angle;
}

GLfloat* Robot::getLightPosition()
{
	return light_position;
}
GLfloat* Robot::getLightDirection()
{
	return light_direction;
}

void Robot::addCamera()
{
	camera = new cugl::Camera();
}

void Robot::rotateCameraLeft()
{
	if(angleCam <= angle + 40)
		angleCam+= 10;
	refreshPositionCamera();
}

void Robot::rotateCameraRight()
{
	if(angleCam >= angle - 40)
		angleCam-= 10;
	refreshPositionCamera();
}

void Robot::tiltUp()
{
	if(angleCamTilt <= 20)
		angleCamTilt += 10;
	refreshPositionCamera();
}

void Robot::tiltDown()
{
	if(angleCamTilt >= -20)
		angleCamTilt -= 10;
	refreshPositionCamera();
}

void Robot::resetCamera()
{
	angleCam = 0;
	refreshPositionCamera();
}


void Robot::turnLightOff()
{
	robotLight->turnOff();
}

void Robot::turnLightOn()
{
	robotLight->turnOn();
}

void Robot::refreshPositionCamera()
{
	camera->set(cugl::Point( x + 0.5, y + height + 0.2, z + 0.5), cugl::Point(x + 0.5 + sin(PI*angleCam/180), y + height + 0.2 + sin(PI*angleCamTilt/180), z + 0.5 + cos(PI*angleCam/180)), cugl::Vector(0, 1, 0).unit());
	light_position[0] = x;
	light_position[1] = height;
	light_position[2] = z;
	light_position[3] = 1.0;
	light_direction[0] = 0;
	light_direction[1] = -height;
	light_direction[2] = height*tan(70.0);

	// update light
	robotLight->setPosition(light_position[0], light_position[1], light_position[2]);
	robotLight->setDirection(camera->getDirection()[0] - light_position[0], -light_position[1], camera->getDirection()[2] - light_position[2]);
	robotLight->setCutOffAngle(35);

}

void Robot::setLocation(GLfloat xAxis, GLfloat yAxis, GLfloat zAxis)
{
	if (xAxis < sizeX && zAxis < sizeZ && xAxis > 0 && zAxis > 0)
	{
		x = xAxis;
		y = yAxis;
		z = zAxis;
		refreshPositionCamera();
		map->setLocation(id, x, y, z, height);
		if (missilesMunition)
			missilesMunition->setPosition(x,y,z);
		if(cannonMunition)
			cannonMunition->setPosition(x,y,z);
		if(phaserMunition)
			phaserMunition->setPosition(x,y,z);
	}
}

bool Robot::move(GLfloat xAxis, GLfloat yAxis, GLfloat zAxis)
{
	int id = map->move(xAxis, yAxis, zAxis, x, y, z);
	if(!id)
	{
		x = xAxis;
		y = yAxis;
		z = zAxis;
		refreshPositionCamera();
		if (missilesMunition)
			missilesMunition->setPosition(x,y,z);
		if(cannonMunition)
			cannonMunition->setPosition(x,y,z);
		if(phaserMunition)
			phaserMunition->setPosition(x,y,z);
		return true;
	}

	else if(!tracks)
	{
		// rubble
		if(id == -2)
		{
			x = xAxis;
			y = yAxis;
			z = zAxis;
			refreshPositionCamera();
			if (missilesMunition)
				missilesMunition->setPosition(x,y,z);
			if(cannonMunition)
				cannonMunition->setPosition(x,y,z);
			if(phaserMunition)
				phaserMunition->setPosition(x,y,z);
			return true;
		}
	}

	return false;
}

bool Robot::moveForward()
{
	//move(x + sin(PI*angle/180), y, z + cos(PI*angle/180));
	if(angle == 0)
		return move(x, y, z + 1);
	else if(angle == 90)
		return move(x + 1, y, z);
	else if(angle == 180)
		return move(x, y, z - 1);
	else
		return move(x - 1, y, z);
}

bool Robot::moveBackward()
{
	//move(x - sin(angle), y, z - cos(angle));
	//move(x - sin(PI*angle/180), y, z - cos(PI*angle/180));
	if(angle == 0)
		return move(x, y, z - 1);
	else if(angle == 90)
		return move(x - 1, y, z);
	else if(angle == 180)
		return move(x, y, z + 1);
	else
		return move(x + 1, y, z);
}

void Robot::moveUp()
{
	if(antigravUnit)
	{
		move(x, y+1, z);
	}
}

void Robot::moveDown()
{
	if(antigravUnit)
	{
		move(x, y-1, z);
	}
}

void Robot::rotate(GLfloat a)
{
	angle = angle + a;
	angleCam = angleCam + a;
	if (angle >= 360)
		angle = 0;
	else if(angle == -180)
		angle = 180;

	refreshPositionCamera();
	for (int i =0; i!=6; ++i)
	{
			if (vect[i])
				vect[i]->setAngle(angle);
	}

	if(missilesMunition)
		missilesMunition->setAngle(angle);
	if(cannonMunition)
		cannonMunition->setAngle(angle);
	if(phaserMunition)
		phaserMunition->setAngle(angle);
}

//modify the for loop (use iterators instead)
void Robot::display()
{
	if(!destroyed)
	{
		if(randomFlag)
		{		
			timerRandom = (++timerRandom)%SPEED_RANDOM_ROBOT;
			if(!timerRandom)
			{
				/*float tmp = rand()%10*0.1;
				if(!tmp || tmp==0.5 || tmp==1)
				{
					int tmp2 = rand()%2;
					int p = pow(-1.0, tmp2);
					rotate(p*tmp*PI);
				}
				if(!moveForward())
					rotate(PI);*/
				int tmp = rand()%4;
				if(!tmp)
					rotate(90);
				else if(tmp == 1)
					rotate(-90);

				if(!moveForward())
					rotate(90);
			}
		}

		glPushMatrix();
			glTranslatef(x + 0.5, y, z + 0.5);
			glRotatef(angle, 0, 1, 0);
			glPushMatrix();
				for (int i =0; i!=6; ++i){
					if (vect[i] != 0){
						glPushMatrix();
							vect[i]->display();
						glPopMatrix();
					}
				}			
			glPopMatrix();
		glPopMatrix();
		glPushMatrix();
			glTranslatef(x + 0.5, y, z + 0.5);
			if(missilesMunition)
				missilesMunition->display();
			if(cannonMunition && cannonMunition->isAnimated())
				cannonMunition->display();
			if(phaserMunition && phaserMunition->isAnimated())
				phaserMunition->display();
		glPopMatrix();
	}
	if(pc)
	{
		pc->animate();
		deleteO = pc->isFinished();
	}
}

void Robot::fire()
{
	if(y == 0)
	{
		if(missilesMunition)
			missilesMunition->fire();
		if(cannonMunition)
			cannonMunition->fire();
		if(phaserMunition)
			phaserMunition->fire();
	}
}

void Robot::fireMissiles()
{
	if(missilesMunition && y == 0)
		missilesMunition->fire();
}

void Robot::fireCannon()
{
	if(cannonMunition && y == 0)
		cannonMunition->fire();
}

void Robot::firePhaser()
{
	if(phaserMunition)
		phaserMunition->fire();
}

void Robot::animate()
{
	if(missilesMunition)
	{
		missilesMunition->animate();
		if(missilesMunition->collision())
		{
			(*mapRobots)[missilesMunition->getCollisionID()]->damage(missilesMunition->getDamage());
		}

	}
	if(cannonMunition)
	{
		cannonMunition->animate();
		if(cannonMunition->collision())
		{
			(*mapRobots)[cannonMunition->getCollisionID()]->damage(cannonMunition->getDamage());
		}
	}
	if(phaserMunition)
	{
		phaserMunition->animate();
		if(phaserMunition->collision())
		{
			(*mapRobots)[phaserMunition->getCollisionID()]->damage(phaserMunition->getDamage());
		}
	}
}

void Robot::switchTexture()
{
	for (int i =0; i!=6; ++i){
		if (vect[i] != 0){
			vect[i]->switchTexture();
		}
	}

	if(missilesMunition)
		missilesMunition->switchTexture();

	if(bipod)
		currentTexture = bipod->getTexture();
	else if(antigravUnit)
		currentTexture = antigravUnit->getTexture();
	else if(tracks)
		currentTexture = tracks->getTexture();
	if(pc)
		pc->setTexture(currentTexture);
}

void Robot::setID(int i)
{
	id = i;
}

int Robot::getID()
{
	return id;
}

void Robot::setMapRobots(std::map<int, Robot*> *mr)
{
	mapRobots = mr;
}

void Robot::damage(int d)
{
	//std::cout << "Maxlife : "<< maxLife <<" life of robot " << id << " : " << life << std::endl;
	life -= d;
	//std::cout << "\tdamage received... life : " << life << std::endl;
	if(life <= 0)
	{
		//std::cout << "Robot " << id << " destoyed...." << life << std::endl;
		destroyed = true;
		if(!pc)
		{
			pc = new ParticleCollision(x + 0.5, height*0.5, z + 0.5);
			pc->setTexture(currentTexture);
		}
		else
			pc->setLocation(x + 0.5, height*0.5, z + 0.5);
	}
}

void Robot::displayLife()
{
	if(life >= 0)
	{
		glPushMatrix();
			glDisable(GL_CULL_FACE);
			glBindTexture(GL_TEXTURE_2D, textureLife);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

			glTranslatef(x + 0.5, height + 0.5, z + 0.5);
			glRotatef(angle, 0, 1, 0);
			glBegin(GL_QUADS);
				glColor3f(1,1,1);
				glNormal3f( 0.0, 0.0, 1.0);
				glTexCoord2f(0.0f + (1.0f - life/maxLife)*0.5f, 0.0f);
				glVertex3f(-0.5f, 0.0f, 0.0f);
				glTexCoord2f(0.5f + (1.0f - life/maxLife)*0.5f, 0.0f);
				glVertex3f(0.5f, 0.0f, 0.0f);
				glTexCoord2f(0.5f + (1.0f - life/maxLife)*0.5f, 1.0f);
				glVertex3f(0.5f, 0.0625f, 0.0f);
				glTexCoord2f(0.0f + (1 - life/maxLife)*0.5, 1.0f);
				glVertex3f(-0.5f, 0.0625f, 0.0f);
			glEnd();
			glEnable(GL_CULL_FACE);
		glPopMatrix();
	}
}

bool Robot::deleteRobot()
{
	return deleteO;
}

Robot::~Robot(void)
{
//	std::cout << "DELETE ROBOT " << id << std::endl;

	// remove the position in the map 
	map->removeObject(x, z);

	delete antigravUnit;
	delete bipod;
	delete cannon;
	delete missiles;
	delete nuclear;
	delete eBrain;
	delete phaser;
	delete tracks;
	delete missilesMunition;
	delete cannonMunition;
	delete phaserMunition;
	delete pc;
	delete robotLight;
	//delete vect;
	
	map = 0;
	mapRobots = 0;
}